package com.deng.api.security;


import com.deng.api.jwt.JWTAuthorizationTokenFilter;
import com.deng.api.service.impl.UserDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * 前后端分离
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailServiceImpl userDetailService;

    @Autowired
    private JWTAuthorizationTokenFilter jwtAuthorizationTokenFilter;

    @Autowired
    private AjaxAuthenticationEntryPoint ajaxAuthenticationEntryPoint;

    @Autowired
    private AjaxAccessDeniedHandler ajaxAccessDeniedHandler;
    @Autowired
    private LogoutHandler logoutHandler;

    /**
     * 配置认证用户和角色的信息的，这些可以是定义好或者数据库中
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //基于数据库信息的认证，并指定密码的加密方式
        auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder());

    }

    /**
     * SpringSecurity要求密码进行加密处理,这里使用BCrypt加密处理
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 用来配置那些web资源的忽略拦截的，一般用来配置静态资源
     *
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        //忽略swagger配置
        web.ignoring().antMatchers(
                "/druid/**",
                "/doc.html",//美化ui
                "/swagger-ui.html",//swagger2
                "/webjars/**",
                "/swagger-resources/**",
                "/v2/*"
        );
    }

    /**
     * 配置web请求相关的：自定义登录、登录参数名、登录成功失败、注销等处理等操作
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //开启支持CORS资源共享-跨域
        http.cors();
        // 关闭csrf防御
        http.csrf().disable();
        //忽略验证码、登录接口
        http.authorizeRequests().antMatchers("/auth/code").permitAll();
        http.authorizeRequests().antMatchers("/auth/login").permitAll();

        //其他接口要进行认证
        http.authorizeRequests().anyRequest().authenticated();
        //未登录处理
        http.httpBasic().authenticationEntryPoint(ajaxAuthenticationEntryPoint);
        //权限不足配置
        http.exceptionHandling().accessDeniedHandler(ajaxAccessDeniedHandler);

        //动态权限
        //登录---自定义登录，有验证码

        //注销功能
        http.logout(out->{
            out.logoutUrl("/auth/logout")
            .logoutSuccessHandler(logoutHandler)
            .invalidateHttpSession(true).clearAuthentication(true).permitAll();
        });

        /**
         *  JWT认证配置
         *     说明：虽然使用token认证方式，但是session依然不禁用。
         *      因为目前验证码功能需要使用session验证，等以后学习了redis之后就可以放到redis中验证了。
         */
//        http.headers().cacheControl();
//        http.addFilterBefore(jwtAuthorizationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        //jwt认证配置
        http.addFilterBefore(jwtAuthorizationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        //关闭session，启用token，删除缓存
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().headers().cacheControl();

    }
}
